package dian.qing.li.demo.security.utils;

import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.pactera.redis.utils.RedisUtils;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;
import org.apache.commons.lang3.StringUtils;

import java.net.UnknownHostException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.List;
import java.util.UUID;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 生成编码工具类
 *
 * @author: liqingdian
 */
@Slf4j
@UtilityClass
public class CodeUtils {

    /**
     * 获取UUID唯一编码
     *
     * @Author: liqingdian
     */
    public static String getGuid() {
        return getGuid(UUID.randomUUID().toString());
    }

    /**
     * 获取UUID唯一编码
     *
     * @param salt 盐
     * @Author: liqingdian
     */
    public static String getGuid(String salt) {
        String uuid = UUID.randomUUID().toString();
        String ip = "";
        String localHostName = "";
        try {
            ip = IpToolUtils.getLocalIP();
            localHostName = IpToolUtils.getLocalHostName();
        } catch (UnknownHostException e) {
            log.error(e.getMessage(), e);
        }
        String text = Joiner.on("-").join(uuid, salt, ip, localHostName, DateUtils.getSystemTime());
        return MD5Utils.md5(text);
    }

    /**
     * 获取唯一编码
     *
     * @param redisKey 缓存Key
     * @param prefix   前缀
     * @param length   限制长度
     * @param init     初始值
     * @Author: liqingdian
     */
    public static String getNumCode(String redisKey, String prefix, int length, long init) {
        return RedisUtils.getNumCode(redisKey, prefix, length, init);
    }

    /**
     * 获取唯一编码
     *
     * @param redisKey 缓存Key
     * @param prefix   前缀
     * @param init     初始值
     * @Author: liqingdian
     */
    public static String getNumCode(String redisKey, String prefix, long init) {
        return getNumCode(redisKey, prefix, 10, init);
    }

    /**
     * 获取指定1~9位数随机字符
     * 采用安全的生成随机数方法（SecureRandom）
     *
     * @param len 随机位数 >0 & <11
     * @Author: liqingdian
     */
    public static String getRandomCode(int len) {
        if (len < 1 || len > 10) {
            len = 10;
        }
        final String base = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
        StringBuffer sb = new StringBuffer();
        SecureRandom secureRandom;
        try {
            secureRandom = SecureRandom.getInstance("SHA1PRNG");
        } catch (NoSuchAlgorithmException e) {
            return "";
        }
        for (int i = 0; i < len; i++) {
            int number = secureRandom.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }

    /**
     * 将驼峰字段转换成分隔符拼接的小写字段 例如：updateTime -> update_time
     *
     * @param field     字段
     * @param separator 分隔符
     * @Author: liqingdian
     */
    public static String underlineField(String field, String separator) {
        Assert.isNotBlank(field, "[field]不能为空");
        Assert.isNotBlank(separator, "[separator]不能为空");
        field = field.trim();
        char[] chars = new char[field.length()];
        field.getChars(0, field.length(), chars, 0);
        StringBuilder builder = new StringBuilder();
        String upper = "[A-Z]";
        Pattern upperP = Pattern.compile(upper);
        for (char name : chars) {
            String input = String.valueOf(name);
            if (upperP.matcher(input).matches()) {
                if (builder.length() > 0) {
                    builder.append(separator).append(input.toLowerCase());
                } else {
                    builder.append(input.toLowerCase());
                }
            } else {
                builder.append(input);
            }
        }
        return builder.toString();
    }

    /**
     * 将属性字段转换称数据库驼峰_字段 例如：updateTime -> update_time
     *
     * @param field 字段
     * @Author: liqingdian
     */
    public static String underlineField(String field) {
        return underlineField(field, "_");
    }

    /**
     * 将分隔符拼接的字段转驼峰 例如：update_time -> updateTime
     *
     * @param field     字段
     * @param separator 分隔符
     * @Author: liqingdian
     */
    public static String humpField(String field, String separator) {
        Assert.isNotBlank(field, "[field]不能为空");
        Assert.isNotBlank(separator, "[separator]不能为空");
        String[] split = field.split(separator);
        List<String> collect = Lists.newArrayList(split)
                .stream()
                .filter(StringUtils::isNotBlank)
                .map(String::toLowerCase).collect(Collectors.toList());
        StringBuilder builder = new StringBuilder();
        for (int i = 0, len = collect.size(); i < len; i++) {
            String str = collect.get(i);
            if (i == 0) {
                builder.append(str);
            } else {
                builder.append(str.substring(0, 1).toUpperCase()).append(str.substring(1));
            }
        }
        return builder.toString();
    }

    /**
     * 将下滑线的数据库字段转驼峰 例如：update_time -> updateTime
     *
     * @param field 字段
     * @Author: liqingdian
     */
    public static String humpField(String field) {
        return humpField(field, "_");
    }

    /**
     * 获取字符串拼音的第一个字母
     *
     * @param chinese 汉字
     * @return
     */
    public static String toPinyinFirstChar(String chinese) {
        StringBuilder pinyin = new StringBuilder();
        //转为单个字符
        HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat();
        char[] newChar = chinese.toCharArray();
        defaultFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);
        defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
        for (int i = 0; i < newChar.length; i++) {
            if (newChar[i] > 128) {
                try {
                    pinyin.append(PinyinHelper.toHanyuPinyinStringArray(newChar[i], defaultFormat)[0].charAt(0));
                } catch (BadHanyuPinyinOutputFormatCombination e) {
                    e.printStackTrace();
                }
            } else {
                pinyin.append(newChar[i]);
            }
        }
        return pinyin.toString();
    }

    /**
     * 汉字转为拼音
     *
     * @param chinese 汉字
     * @return
     */
    public static String toPinyin(String chinese) {
        StringBuilder pinyin = new StringBuilder();
        char[] newChar = chinese.toCharArray();
        HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat();
        defaultFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);
        defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
        for (int i = 0; i < newChar.length; i++) {
            if (newChar[i] > 128) {
                try {
                    pinyin.append(PinyinHelper.toHanyuPinyinStringArray(newChar[i], defaultFormat)[0]);
                } catch (BadHanyuPinyinOutputFormatCombination e) {
                    log.error(e.getMessage(), e);
                }
            } else {
                pinyin.append(newChar[i]);
            }
        }
        return pinyin.toString();
    }
}